#include <stdbool.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include "anet.h"


static int llisten(lua_State* L)
{
    const char* host = luaL_checkstring(L,1);
    int port = luaL_checkinteger(L,2);
    int backlog = luaL_optinteger(L,3,32);
    int fd = anet_tcp_listen(host,port,backlog);
    if(fd<=0)
    {
        return luaL_error(L,"listen error.");
    }
    lua_pushinteger(L,fd);
    return 1;
}

static int ltcp_accept(lua_State* L)
{
    char ipstr[30]={};
    int port;
    int listenfd = luaL_checkinteger(L,1);
    int clientfd = anet_tcp_accept(listenfd,ipstr,&port);
    if(clientfd>0)
    {
        lua_pushinteger(L,clientfd);
        lua_pushstring(L,ipstr);
        lua_pushinteger(L,port);
        return 3;
    }
	lua_pushinteger(L,0);
    lua_pushstring(L,"");
    lua_pushinteger(L,0);
    return 3;
}

static int ltcp_connect(lua_State* L)
{
    const char* ip = luaL_checkstring(L,1);
    int port = luaL_checkinteger(L,2);
    int timeout = luaL_checkinteger(L,3);
    int fd = anet_tcp_connect(ip,port,timeout);
    if(fd<=0)
    {
        //printf("connect error.\n");
    }
    lua_pushinteger(L,fd);
    return 1;
}


static int ltcp_close(lua_State* L)
{
    int fd = luaL_checkinteger(L,1);
    int ret = anet_close(fd);
    lua_pushinteger(L,ret);
    return 1;
}

static int ltcp_read(lua_State* L)
{
    int fd = luaL_checkinteger(L,1);
    int sz = luaL_optinteger(L,2,1024);
    if(sz>1024)
        sz = 1024;
    char buff[1024];
    int ret = anet_tcp_read(fd,buff,sz);
    lua_pushinteger(L,ret);
    if(ret<0)
    {
        //lua_pushstring(L,strerror(errno));
		lua_pushstring(L,"");
        return 2;
    }
    lua_pushlstring(L,buff,ret);
    return 2;
}

static int ltcp_write(lua_State* L)
{
    int fd = luaL_checkinteger(L,1);
    size_t sz;
    const char* buff = luaL_checklstring(L,2,&sz);
    int ret = anet_tcp_write(fd,buff,sz);
    lua_pushinteger(L,ret);
    if(ret<0)
    {
        //lua_pushstring(L,strerror(errno));
		lua_pushstring(L,"");
        return 2;
    }
    return 1;
}

static int ltcp_set_nblock(lua_State* L)
{
    int fd = luaL_checkinteger(L,1);
    int opt = luaL_checkinteger(L,2);
    int ret = anet_tcp_set_nblock(fd,opt>0);
    lua_pushinteger(L,ret);
    if(ret<0)
    {
        //lua_pushstring(L,strerror(errno));
		lua_pushstring(L,"");
        return 2;
    }
    return 1;
}

static int ltcp_set_addr_reuse(lua_State* L)
{
    int fd = luaL_checkinteger(L,1);
    int ret = _anet_set_reuse_addr(fd);
    lua_pushinteger(L,ret);
    if(ret<0)
    {
        //lua_pushstring(L,strerror(errno));
		lua_pushstring(L,"");
        return 2;
    }
    return 1;
}

static const struct luaL_Reg libanet[]=
{
    {"listen",llisten},
    {"accept",ltcp_accept},
    {"connect",ltcp_connect},
    {"read",ltcp_read},
    {"write",ltcp_write},
    {"close",ltcp_close},
    {"noblock",ltcp_set_nblock},
    {"addrreuse",ltcp_set_addr_reuse},
    {NULL,NULL}
};

// lua statemant 'local anet = require "cosocket.anet"' will call "luaopen_cosocket_anet" function
int luaopen_cosocket_anet(lua_State* L)
{
    //luaL_newlib(L,libanet);// lua5.3
    luaL_openlib(L,"anet",libanet,0);
    return 1;
}







